home *** CD-ROM | disk | FTP | other *** search
/ Programming Sound Cards / Programming Sound Cards.iso / sound_52 / harmoniz.ma < prev    next >
Text File  |  1995-01-01  |  14KB  |  510 lines

  1. export
  2.     modalHarmonize,
  3.     chordHarmonize,
  4.     parallelHarmonize, 
  5.     majorHarmonize
  6. end
  7.  
  8. #
  9. # closed voicing harmonization.
  10. #
  11. # Routines here basically give closed voicings via
  12. # a harmonization of a high melody voice. No attention
  13. # is paid to voice leading from previous chord.
  14. #
  15. # routines for harmonizing a melody note
  16. #
  17. # 1. modalHarmonize - produce chord in scale that corresponds to
  18. #    modal harmony; e.g., given B in C IONIAN scale returns Major7,  C,E,G,B
  19. #                 given C in C IONIAN scale returns Dminor7,
  20. #                            LD,LF,LA,C.
  21. #    Can handle modal scales only.
  22. #
  23. # 2. chordHarmonize - harmonize melody note according to current chord.
  24. #    chord passed in is used and may be inverted.
  25. #    Handles most (if not all) chords.
  26. #
  27. # 3. parallelHarmonize - Parallel motion may be supported 
  28. #    by saving the last melody note
  29. #     and the last returned harmony chord and then subtracing the
  30. #     difference between the new melody note and last melody note
  31. #     to produce the new harmony chord. A routine is provided to do this.
  32. #
  33. # 4. majorHarmonize - harmonizes melody note based on root I ii iii IV V vi vii0
  34. #    harmonic assumption. Thus if used be careful of harmonic
  35. #    root; e.g., if tracking via chord then harmonize as follows;
  36. #    
  37. #        major - I, IV
  38. #            minor - ii, iii, vi
  39. #        dom   - V
  40. #        dim   - vii0
  41. #
  42. # 5. harmonizeDominant() - different close harmony for dominant - uses
  43. #    flatted 5th rule (dom7 on minor 2nd of root). NOT IMPLEMENTED.
  44. #
  45. # 6. minorHarmonize - similar to majorHarmonize but use traditional
  46. #    minor chords. NOT IMPLEMENTED.
  47.  
  48. # turn on for standalone test
  49. # otherwise include these two before this include library.
  50. @include \mh\scales.mh
  51. @include \mh\chords.mh
  52.  
  53. #
  54. # modalHarmonize()
  55. #
  56. # Given the following inputs:
  57. #    pointer to integer output array of size 3
  58. #    scaleCount - number of indices into scale array
  59. #    pointer to scale array
  60. #    root offset - i.e., offset value for current note
  61. #        where note is formed by octave+root+offset
  62. #
  63. # produce a "harmony" chord from the inputs.
  64. # We find the associated "offsets" down a third, fifth, 
  65. # and seventh from the input offset which is assumed to
  66. # be the top melody note.
  67. #
  68. # The returned offsets taken together with the input offset
  69. # can be used to form a 4 note harmonized chord. This
  70. # will be built from the associated scale and thus represents
  71. # a simple harmonization. The chord is built as follows:
  72. #    melody = octave+root+offset
  73. #    third down = octave+root+output[2] 
  74. #    fifth down = octave+root+output[1] 
  75. #    seventh down = octave+root+output[0] 
  76. #
  77. # CAVEATS:
  78. #    This routine makes sense for normal scales. If
  79. #    the scales are far out; so will be the results.
  80. #    
  81. #    It also isn't very interesting to call this over
  82. #    and over again for a harmonization. The
  83. #    high level routines may use this as a basic tool,
  84. #    but should also use a certain amount of diminished
  85. #    and/or same chord (if Dom7, then use Dom7) to
  86. #    provide variety.
  87. #
  88. # Also:
  89. #    . not suitable for 1st/last note in chord.
  90. #    . not normal for "thickened" line.
  91. #    
  92.  
  93. riff modalHarmonize(int vector output, scaleCount, vector scale, offset)
  94. # vector output, lower 3 notes of chord, 4 voice chord including top note
  95. #    note that this must be an integer vector due to negative
  96. #    subtraction trick, below.
  97. # scale index
  98. # note offset (note is assumed to be octave+root+rootOffset)
  99.     int thirdOffset
  100.     int fifthOffset
  101.     int seventhOffset
  102.     int i
  103.  
  104.     # find offset value
  105.     for ( i = 0; i < scaleCount; i++)
  106.         if (scale[i] == offset)
  107.             break
  108.         end
  109.     end
  110.     # ASSERTION
  111.     if ( i == scaleCount)
  112.         void printf("did not find rootOffset in scale\n")
  113.         return(0)
  114.     end
  115.     # i is associated scale index
  116.  
  117.     # first third down
  118.     thirdOffset = i - 2 
  119.     if (thirdOffset < 0)
  120.         thirdOffset = scaleCount + thirdOffset
  121.         output[2] = scale[thirdOffset] - 12
  122.     else
  123.         output[2] = scale[thirdOffset]
  124.     end
  125.  
  126.     # fifth down
  127.     fifthOffset = i - 4 
  128.     if (fifthOffset < 0)
  129.         fifthOffset = scaleCount + fifthOffset
  130.         output[1] = scale[fifthOffset] - 12
  131.     else
  132.         output[1] = scale[fifthOffset] 
  133.     end
  134.  
  135.     # 7th down
  136.     seventhOffset = i - 6 
  137.     if (seventhOffset < 0)
  138.         seventhOffset = scaleCount + seventhOffset
  139.         output[0] = scale[seventhOffset] - 12
  140.     else
  141.         output[0] = scale[seventhOffset] 
  142.     end
  143. end
  144.  
  145. #
  146. # chordHarmonize()
  147. # harmonize a melody note to a certain CHORD pattern
  148. #
  149. # returns chord with ROOT; E.g., if C chord and D melody
  150. # note; you get back a harmony chord in closed position
  151. # that has a C root. The chord maybe inverted. The chord
  152. # notes are chosen as close as possible down from
  153. # the melody note. No attention is giving to voice leading.
  154. #
  155. # Can handle 2,3,and more note chords. If chord is bigger
  156. # than 3 notes; the chordSize is used for determining lower
  157. # offsets returned. 
  158. #
  159. riff chordHarmonize(int vector output, melOffset, vector chordInput, chordSize)
  160. # output - array for 3 three lower harmony voices
  161. # melOffset - (octave,root,offset) form of lead melody note. 
  162. # vector chordInput - row pointer to chord in chordNotes array.
  163. # chordSize - max notes in chord.
  164. #
  165. # returns:
  166. #    number of notes used in output array. E.g., 3 means 
  167. #    3 voice chord. 2 means 2 voice chord. 
  168.     int chordIndex
  169.     int noback
  170.  
  171.     # map offset into chord index
  172.     # we find first chord degree greater than or equal to
  173.     # melody offset
  174.     for ( chordIndex = 0; chordIndex < chordSize; chordIndex++)
  175.         if (chordInput[chordIndex] >= melOffset)
  176.             break
  177.         end
  178.     end
  179.     if (chordIndex == chordSize)
  180.         chordIndex--
  181.     end
  182.     #void printf("chordSize %d, chordIndex %d [] %d, melOffset %d\n", chordSize, chordIndex, chordInput[chordIndex], melOffset)
  183.     # chordIndex is first chord degree GREATER than or same as melody note
  184.     # this means that previous chord degree is less than melody note.
  185.  
  186.     switch(chordSize)
  187.     # 2 note chords
  188.     case 2:
  189.         noback = 3 - chordIndex
  190.         switch(noback)
  191.         # 0 can't happen
  192.         case 1:
  193.             output[2] = chordInput[1]   
  194.             output[1] = chordInput[0]   # unison
  195.             output[0] = chordInput[1] - 12
  196.             end
  197.         case 2:
  198.             output[2] = chordInput[0]    # unison 
  199.             output[1] = chordInput[1] - 12  
  200.             output[0] = chordInput[0] - 12  
  201.             end
  202.         # complete octave down
  203.         case 3:
  204.             output[2] = chordInput[1] - 12 
  205.             output[1] = chordInput[0] - 12 
  206.             output[0] = chordInput[1] - 24 
  207.             end
  208.         default:
  209.             void printf("%d %d invalid interval calculation\n",chordSize,chordIndex)
  210.             end
  211.  
  212.         end
  213.         end
  214.     # 3 note chords
  215.     case 3:
  216.         noback = 3 - chordIndex
  217.         switch(noback)
  218.         case 0:
  219.             output[2] = chordInput[2]   # 5th
  220.             output[1] = chordInput[1]   # 3rd
  221.             output[0] = chordInput[0]   # unison
  222.             end
  223.         case 1:
  224.             output[2] = chordInput[1]   # 3rd  
  225.             output[1] = chordInput[0]   # unison
  226.             output[0] = chordInput[2] - 12    # 5th 
  227.             end
  228.         case 2:
  229.             output[2] = chordInput[0]    # unison 
  230.             output[1] = chordInput[2] - 12  # 5th
  231.             output[0] = chordInput[1] - 12  # 3rd
  232.             end
  233.         # complete octave down
  234.         case 3:
  235.             output[2] = chordInput[2] - 12  # 5th
  236.             output[1] = chordInput[1] - 12  # 3rd
  237.             output[0] = chordInput[0] - 12  # unison
  238.             end
  239.         default:
  240.             void printf("%d %d invalid interval calculation\n",chordSize,chordIndex)
  241.             end
  242.  
  243.         end
  244.         end
  245.     # more than 3
  246.     default:
  247.         noback = 3 - chordIndex
  248.         switch(noback)
  249.         case 0:
  250.             output[2] = chordInput[2]   # 5th
  251.             output[1] = chordInput[1]   # 3rd
  252.             output[0] = chordInput[0]   # unison
  253.             end
  254.         case 1:
  255.             output[2] = chordInput[1]   # 3rd  
  256.             output[1] = chordInput[0]   # unison
  257.             output[0] = chordInput[chordSize-1] - 12    # 7th 
  258.             end
  259.         case 2:
  260.             output[2] = chordInput[0]    # unison 
  261.             output[1] = chordInput[chordSize-1] - 12  # 7th
  262.             output[0] = chordInput[chordSize-2] - 12  # 5rd
  263.             end
  264.         # complete octave down
  265.         case 3:
  266.             output[2] = chordInput[chordSize-1] - 12  # 7th
  267.             output[1] = chordInput[chordSize-2] - 12  # 5th
  268.             output[0] = chordInput[chordSize-3] - 12  # 3rd
  269.             end
  270.         default:
  271.             void printf("%d %d invalid interval calculation\n",chordSize,chordIndex)
  272.             end
  273.  
  274.         end
  275.         end
  276.     end
  277. end
  278.  
  279. #
  280. # parallelHarmonize()
  281. #
  282. # return parallel harmony chord.
  283. #
  284. # Caveats:
  285. #     You can't do it on the first chord obviousally
  286. #
  287. # difference. positive or negative offset from previous melody note
  288. #     e.g., C -> D, then 2, C -> LBb then -2.    should be new - old.
  289. riff parallelHarmonize(int vector output, melOffset, difference)
  290.     output[0] = output[0] + difference
  291.     output[1] = output[1] + difference
  292.     output[2] = output[2] + difference
  293.     return(melOffset+difference)
  294. end
  295.  
  296. #
  297. # majorHarmonize
  298. #
  299. # expect offset that corresponds to major scale offsets.
  300. # returns harmony chord based on standard major root harmony.
  301. #    I ii iii IV V vi vii0.
  302. #
  303. # Chords returned are basically either major or dominant
  304. # harmony (not too racy here). 
  305. #
  306. riff majorHarmonize(int vector output, offset)
  307. # vector output, lower 3 notes of chord, 4 voice chord including top note
  308. #    note that this must be an integer vector due to negative
  309. #    subtraction trick, below.
  310. # offset - IONIAN scale offset 0,2,4,5,7,9,11
  311. #    (unison)0 - returns major chord
  312. #    (2nd)   2 - returns vii0 OR V7 (random)
  313. #    (3rd)   4 - returns major chord
  314. #    (4th)   5 - returns vii0 or V7
  315. #    (5th)   7 - returns major
  316. #    (6th)   9 - returns vii0/ii
  317. #    (7th)   11 - returns major
  318. #
  319.     int rval
  320.     rval = mchoose(0,1)
  321.     switch(offset)
  322.     # unison, return Major inverted on 3rd
  323.     case 0:
  324.         output[0] = {-8}  # third
  325.         output[1] = {-5}  # fifth 
  326.         if (rval)
  327.             output[2] = {-3}  # sixth
  328.         else
  329.             output[2] = {-1}  # seventh
  330.         end
  331.         end
  332.     # 2nd, return Dom7 or vii0 half/dim.
  333.     # Dom7 is inverted on 7th, vii inverted on 5th
  334.     case 2:
  335.         output[0] = {-7}  # fourth
  336.         if (rval)
  337.             output[1] = {-5}  # fifth
  338.         else
  339.             output[1] = {-3}  # sixth
  340.         end
  341.         output[2] = {-1} # seventh 
  342.         end
  343.     # 3rd, return major 6/7 inverted on 5rd
  344.     case 4:
  345.         output[0] = {-5}    # 5th
  346.         if (rval)
  347.             output[1] = {-3}    # 6th
  348.         else
  349.             output[1] = {-1}    # 7th
  350.         end
  351.         output[2] = 0        #unison
  352.         end
  353.     # 4th, return Dom/half-dim. Dom rooted on dom unison,
  354.     #    half-dim rooted on 7th
  355.     case 5:
  356.         if (rval)
  357.             output[0] = {-5}    # 5th
  358.         else
  359.             output[0] = {-3}    # 6th
  360.         end
  361.         output[1] = {-1}    #7th
  362.         output[2] = 2    # 2nd
  363.         end
  364.     # 5th, return major chord
  365.     case 7:
  366.         if (rval)
  367.             output[0] = {-3} # 6th
  368.         else
  369.             output[0] = {-1} # 7th
  370.         end
  371.         output[1] = 0    # unison
  372.         output[2] = 4    # 3rd
  373.         end
  374.     # 6th, return half/dim OR minor 2nd.
  375.     case 9:
  376.         if (rval)
  377.             output[0] = {-1} # 7th 
  378.         else
  379.             output[0] = 0
  380.         end
  381.         output[1] = 2    # 2nd
  382.         output[2] = 5    # 4th
  383.         end
  384.     # 7th, return major or Dom7
  385.     case 11:
  386.         if (rval)
  387.             # major
  388.             output[0] = 0
  389.             output[1] = 4    #3rd
  390.             output[2] = 7    #5th
  391.         else
  392.             # dom7
  393.             output[0] = 2    #2nd
  394.             output[1] = 5    #4th
  395.             output[2] = 7    #5th
  396.         end
  397.         end
  398.     default:
  399.         void printf("unknown offset\n")
  400.         end
  401.     end
  402. end
  403.  
  404. # TEST ROUTINES
  405. # commented out at the moment.
  406. ###############################################################
  407.  
  408. #int harmChord[3]
  409. #riff testHarmonize()
  410. #    int i
  411. #    int scaleIndex
  412. #    int melOffset
  413. #
  414. #    for ( scaleIndex = 6; scaleIndex >= 0; scaleIndex--)
  415. #        # pass the following
  416. #        # 1. pointer to output vector of size 3
  417. #        # 2. size of scale
  418. #        # 3. pointer to scale offset row
  419. #        # 4. current roff value
  420. #        melOffset = baseScale[IONIAN][scaleIndex]
  421. #        void chordHarmonize(&harmChord, melOffset, &chordNotes[Major6], chordSizes[Major6])
  422. #        # print out chord from bass to melody
  423. #        for ( i = 0; i < 3; i++)
  424. #            void printf("%n,", C+harmChord[i])
  425. #            C+harmChord[i] 0,q        100
  426. #        end
  427. #        void printf("%n\n",C+melOffset)
  428. #        C+melOffset    q    100
  429. #    end
  430. #end
  431. #
  432. #int aChord[3]
  433. #riff testModalHarmonize()
  434. #    int i
  435. #    int scaleIndex
  436. #
  437. #    for ( scaleIndex = 6; scaleIndex >= 0; scaleIndex--)
  438. #        # pass the following
  439. #        # 1. pointer to output vector of size 3
  440. #        # 2. size of scale
  441. #        # 3. pointer to scale offset row
  442. #        # 4. current roff value
  443. #        void modalHarmonize(&aChord, scaleSizes[DORIAN], &baseScale[DORIAN], baseScale[DORIAN][scaleIndex]) 
  444. #        for ( i = 0; i < 3; i++)
  445. #            void printf("%n,", C+aChord[i])
  446. #            C+aChord[i] 0,q        100
  447. #        end
  448. #        void printf("%n\n",C+baseScale[DORIAN][scaleIndex])
  449. #        C+baseScale[DORIAN][scaleIndex]    q    100
  450. #    end
  451. #end
  452. #
  453. #int hChord[3]
  454. #riff testParallelHarmonize()
  455. #    int i
  456. #    int scaleIndex
  457. #    int melOffset
  458. #    int lastMelOffset
  459. #    int difference
  460. #
  461. #    # play first chord
  462. #    lastMelOffset = baseScale[IONIAN][6]    
  463. #    hChord[2] = baseScale[IONIAN][4]    
  464. #    hChord[1] = baseScale[IONIAN][2]
  465. #    hChord[0] = baseScale[IONIAN][0]
  466. #    for ( i = 0; i < 3; i++)
  467. #        void printf("%n,", C+hChord[i])
  468. #        C+hChord[i] 0,q        100
  469. #    end
  470. #    void printf("%n\n",C+lastMelOffset) 
  471. #    C+lastMelOffset    q    100
  472. #
  473. #    for ( scaleIndex = 5; scaleIndex >= 0; scaleIndex--)
  474. #        # pass the following
  475. #        # 1. pointer to output vector of size 3
  476. #        # 2. size of scale
  477. #        # 3. pointer to scale offset row
  478. #        # 4. current roff value
  479. #        melOffset = baseScale[IONIAN][scaleIndex]
  480. #        difference = melOffset - lastMelOffset
  481. #             void parallelHarmonize(&hChord, melOffset, difference)
  482. #        for ( i = 0; i < 3; i++)
  483. #            void printf("%n,", C+hChord[i])
  484. #            C+hChord[i] 0,q        100
  485. #        end
  486. #        void printf("%n\n",C+baseScale[IONIAN][scaleIndex])
  487. #        C+baseScale[IONIAN][scaleIndex]    q    100
  488. #        lastMelOffset = melOffset
  489. #    end
  490. #end
  491.  
  492. #int rChord[3]
  493. #vco testRoot()
  494. #    int i
  495. #    int index
  496. #    int melOffset
  497. #
  498. #
  499. #    for ( index = 0; index < 7; index++)
  500. #         melOffset = baseScale[IONIAN][index]
  501. #        void majorHarmonize(&rChord, melOffset)
  502. #         for ( i = 0; i < 3; i++)
  503. #             void printf("%n,", C+rChord[i])
  504. #             C+rChord[i] 0,q        100
  505. #         end
  506. #         void printf("%n\n",C+melOffset) 
  507. #         C+melOffset    q    100
  508. #    end
  509. #end
  510.